feat(huddle): multi-machine coordination — sync, fork-proof adopt, idempotent rotation (PP-lt12.38)#1621
Merged
Merged
Conversation
The huddle beads already sync via Dolt/DoltHub, but three mechanisms were machine-local and broke across Tim's Mac + Bazzite: the root-bead pointer, read freshness, and the rotation lock. This adds: - huddle_sync: throttled, PER-MACHINE Dolt push+pull (shared last-pull marker + non-blocking pull.lock in the state dir), wired into the session-start and poll hooks. Fail-open — never blocks a prompt. - huddle_discover_root + auto-adopt: fresh machines adopt the synced "Huddle coordination root" epic instead of forking a duplicate; bootstrap is now discover-before-create. - Idempotent cross-machine rotation: pull-first, adopt-existing-daily-by-title, push-after, plus a deterministic huddle_reconcile_today dedup (canonical = lowest id) run at end of rotation and once per session-start. session-names.json + last-seen cursors stay intentionally machine-local. Tests: new scripts/tests/test_huddle_sync.py (10 cases: throttle math, fail-open, discovery, reconcile). Full check green (80 pytest, 1414 vitest, shellcheck/ruff/yaml clean). Docs: pinpoint-huddle SKILL.md + design spec §14. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
There was a problem hiding this comment.
Pull request overview
This PR upgrades the huddle coordination hooks from a single-machine model to a multi-machine model by leveraging the existing Dolt/DoltHub replication in beads, adding per-machine sync throttling, fork-proof root discovery/adoption, and idempotent rotation/dedup behavior.
Changes:
- Added
huddle_sync(throttled, per-machinebd dolt push/pull) and wired it into session-start and poll hooks to improve cross-machine freshness. - Implemented fork-proof root discovery/auto-adopt (
huddle_discover_root) and rotation idempotency (adopt-if-exists daily/monthly by title), plus a reconcile safety-net (huddle_reconcile_today). - Added Python unit tests covering sync throttling/fail-open behavior, root discovery determinism, and duplicate-daily reconciliation.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/tests/test_huddle_sync.py | Adds unit tests for the new multi-machine sync/discovery/reconcile helpers by stubbing bd and running functions via bash -c. |
| scripts/hooks/huddle-lib.sh | Introduces huddle_sync, huddle_discover_root, and huddle_reconcile_today to support multi-machine coordination. |
| scripts/hooks/huddle-session-start.sh | Runs huddle_sync at session start and auto-adopts an existing root when config.json is missing; runs reconcile safety-net once per session. |
| scripts/hooks/huddle-poll.sh | Runs huddle_sync before reading notes/comments so polls see cross-machine updates with per-machine throttling. |
| scripts/hooks/huddle-rotate.sh | Pulls before the date re-check, adopts existing daily/monthly by title, pushes updated pointers, and invokes reconcile safety-net. |
| scripts/hooks/huddle-bootstrap.sh | Adds discover-and-adopt behavior to prevent cross-machine duplicate root creation. |
| docs/superpowers/specs/2026-05-17-huddle-system-design.md | Updates the huddle design spec to document the multi-machine sync/auto-adopt/rotation model and new state files. |
| .agents/skills/pinpoint-huddle/SKILL.md | Updates the huddle skill reference with multi-machine guidance and new state-file documentation. |
CI runs shellcheck 0.9.0 (exits non-zero on info-level findings that local 0.11.0 doesn't emit). Two fixes: - huddle_reconcile_today: rewrite `[[ -n ]] && bd update || true` (SC2015) as an explicit if. - huddle_sync: pass the marker/interval to the locked body via exported env vars instead of single-quoted `$1/$2` in `bash -c`, removing the SC2016 trigger entirely — mirrors huddle-rotate.sh's do_rotation pattern. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ose, pull-before-reconcile - huddle_sync: wrap bd dolt push/pull in `timeout`/`gtimeout` (cap $HUDDLE_SYNC_TIMEOUT, default 15s) so a hung remote is killed at the cap instead of stalling the hook; soften the "never blocks" comment to "bounded". - huddle_reconcile_today: repoint today_bead.id FIRST (only close duplicates once bd update confirms root points at the canonical), so a failed repoint leaves a harmless open dup rather than a dangling pointer to a closed bead. - huddle-rotate.sh: bd dolt pull once more before huddle_reconcile_today so the safety-net actually sees a peer's duplicate in the double-create race. - SKILL.md: fix broken markdown (bold split across lines rendered as a list). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
The huddle coordination system was designed single-machine. Tim now runs sessions on multiple machines (Mac + Bazzite) with many concurrent sessions per machine. The huddle beads already sync via Dolt embedded + DoltHub (
sync.remotein.beads/config.yaml) — the root bead, itsnotespointers, dailies/monthlies, and comments all replicate viabd dolt push/pull. What was machine-local and broke across machines: the root-bead pointer, read freshness, and the rotation lock.Plan:
/home/froeht/.claude/plans/eager-sprouting-church.md(approved).What changed
huddle_sync(huddle-lib.sh) — throttled, per-machine Dolt push+pull. Sharedlast-pullmarker + non-blockingpull.lockin the state dir (which resolves identically for every worktree/session of a clone), so one sync perHUDDLE_SYNC_SECONDS(default 180) serves all sessions on the machine — not one-per-session. Wired into the session-start and poll hooks. Fully fail-open: offline/bd errors write the marker and return 0, never blocking a prompt.huddle_discover_rootfinds the existing "Huddle coordination root" epic in the synced DB. Session-start auto-adopts it (writesconfig.json) when config is missing instead of nagging;huddle-bootstrap.shdiscovers-before-create. No more duplicate-root fork on a second machine.huddle-rotate.sh) — pull-first (peer-already-rotated → no-op), adopt an existingHuddle daily <today>by title instead of creating a duplicate, push-after.huddle_reconcile_todaydeterministically collapses any residual duplicate (canonical = lowest id) at end of rotation and once per session-start; every machine picks the same winner so they converge.session-names.json(self-filter) andlast-seen-<hash>(poll cursor) — a session lives on one machine, and a peer machine's posts must not be self-filtered on yours.Rotation model decision
Tim chose idempotent adopt-if-exists over a
bd merge-slotcross-machine mutex. The accepted residual race (two machines both create before either pushes) is cleaned deterministically by the reconcile safety-net; rotation is lazy so a transient duplicate is harmless.Tests / verification
scripts/tests/test_huddle_sync.py— 10 cases: throttle fires/skips/stale/interval-0, fail-open on push+pull error, discovery found/lowest-id/none, reconcile collapse + no-op.pnpm run checkgreen: 80 pytest + 1414 vitest, 0 new type errors, shellcheck/ruff/yaml/actionlint/zizmor clean.pinpoint-huddleSKILL.md (Multi-machine section, state-file table) + design spec §14 and revised §9.4.🤖 Generated with Claude Code